package path.calculator;

import static org.junit.Assert.assertEquals;

import org.junit.Test;

public class PathCalculatorTest {
    private PathCalculator calculator;
    private long startTime;

    @Test
    public void noNodesNoPaths() {
        calculator = new PathCalculator(0);
        assertEquals(0, calculator.totalPaths());
    }

    @Test
    public void oneNodeResultsInOnePossiblePath() {
        calculator = new PathCalculator(1);
        int totalPaths = calculator.totalPaths();
        assertEquals(1, totalPaths);

    }

    @Test
    public void twoNodesResultsIn2Paths() {
        calculator = new PathCalculator(2);
        int totalPaths = calculator.totalPaths();
        assertEquals(2, totalPaths);
    }

    @Test
    public void threeNodesNoDependencies6Paths() {
        calculator = new PathCalculator(3);
        int totalPaths = calculator.totalPaths();
        assertEquals(6, totalPaths);
    }

    @Test
    public void fourNodesNoDependencies24Paths() {
        calculator = new PathCalculator(4);
        int totalPaths = calculator.totalPaths();
        assertEquals(24, totalPaths);
    }

    @Test
    public void twoNodesOneDependencyOnePath() {
        calculator = new PathCalculator(2);
        createLine('a', 'b');
        int totalPaths = calculator.totalPaths();
        assertEquals(1, totalPaths);
    }

    @Test
    public void threeNodesInALineOnePath() {
        calculator = new PathCalculator(3);
        createLine('a', 'b');
        createLine('b', 'c');
        int totalPaths = calculator.totalPaths();
        assertEquals(1, totalPaths);
    }

    @Test
    public void fourNodesWithToIndependentDependneciesShouldResultInSixPahts() {
        calculator = new PathCalculator(4);
        createLine('a', 'b');
        createLine('c', 'd');
        int totalPaths = calculator.totalPaths();
        assertEquals(6, totalPaths);
    }

    @Test
    public void twoNodesWithFlowInBothDirectionsShouldResultInNoPaths() {
        calculator = new PathCalculator(2);
        createLine('a', 'b');
        createLine('b', 'a');
        int totalPaths = calculator.totalPaths();
        assertEquals(0, totalPaths);
    }

    @Test
    public void whatIsThreeThreadsTwoStepsEach() {
        calculator = new PathCalculator(6);
        createLine('a', 'b');
        createLine('c', 'd');
        createLine('e', 'f');
        start();
        int totalPaths = calculator.totalPaths();
        stop("3 Threads 2 Opcodes", totalPaths);
    }

    @Test
    public void whatIs2ThreadsAndThreeSteps() {
        calculator = new PathCalculator(6);
        createLine('a', 'b', 'c');
        createLine('d', 'e', 'f');
        start();
        int totalPaths = calculator.totalPaths();
        stop();
        System.out.printf("2 Threads 3 Opcodes %s\n", totalPaths);
    }

    @Test
    public void twoThreadsFourSteps() {
        calculator = new PathCalculator(8);
        createLine('a', 'b', 'c', 'd');
        createLine('e', 'f', 'g', 'h');
        start();
        int totalPaths = calculator.totalPaths();
        stop();
        System.out.printf("2T4S %s\n", totalPaths);
    }

    @Test
    public void twoThreadsFiveSteps() {
        calculator = new PathCalculator(10);
        createLine('a', 'b', 'c', 'd', 'e');
        createLine('f', 'g', 'h', 'i', 'j');
        start();
        int totalPaths = calculator.totalPaths();
        stop();
        System.out.printf("2T5S %s\n", totalPaths);
    }

    @Test
    public void whatIs2threadsAnd6Steps() {
        calculator = new PathCalculator(12);
        createLine('a', 'b', 'c', 'd', 'e', 'f');
        createLine('g', 'h', 'i', 'j', 'k', 'l');
        start();
        int totalPaths = calculator.totalPaths();
        stop();
        System.out.printf("2T6S %s\n", totalPaths);
    }

    @Test
    public void whatIs2ThreadsAnd7Steps() {
        calculator = new PathCalculator(14);
        createLine('a', 'b', 'c', 'd', 'e', 'f');
        createLine('g', 'h', 'i', 'j', 'k', 'l');
        int totalPaths = calculator.totalPaths();
        start();
        System.out.printf("2T7S %s\n", totalPaths);
        stop();
    }

    private void stop(String run, int totalPaths) {
        System.out.printf("Time %dms -- %s: Total paths: ", System.currentTimeMillis() - startTime, run, totalPaths);

    }

    private void start() {
        startTime = System.currentTimeMillis();
    }

    private void createLine(char... values) {
        for (int i = 0; i < values.length - 1; ++i)
            calculator.mustFlowFromNodeToNode(values[i], values[i + 1]);
    }

}
